package com.excel.service.excel.v1;



import cn.hutool.core.util.ObjectUtil;
import com.corpgovernment.api.basic.request.CityInfoQuickDisplayRequest;
import com.corpgovernment.api.basic.response.CityInfoQuickDisplayResponse;
import com.corpgovernment.api.basic.vo.CityBasicInfoVO;
import com.corpgovernment.api.basic.vo.ProvinceInfoVO;
import com.corpgovernment.api.travelstandard.enums.AreaTypeEnum;
import com.corpgovernment.api.travelstandard.vo.AreaConfigVo;
import com.corpgovernment.api.travelstandard.vo.AreaVo;
import com.corpgovernment.common.common.CorpBusinessException;
import com.corpgovernment.common.utils.ObjectStringTrimUtils;
import com.corpgovernment.organization.constant.OrganizationResponseCodeEnum;
import com.corpgovernment.organization.dataloader.BasicDataClientLoader;
import com.corpgovernment.organization.util.ExcelUtils;
import com.corpgovernment.travelstandard.entity.db.HotelAreaConfUpload;
import com.corpgovernment.travelstandard.entity.db.TravelStandardCityConfig;
import com.corpgovernment.travelstandard.entity.db.UploadErrorLog;
import com.corpgovernment.travelstandard.enums.QuarterImportExcelRecordStatusEnum;
import com.corpgovernment.travelstandard.impl.AreaConfigService;
import com.corpgovernment.travelstandard.impl.MbTravelstandHotelService;
import com.corpgovernment.travelstandard.mapper.CityConfigMapper;
import com.corpgovernment.travelstandard.mapper.MbHotelAreaConfUploadMapper;
import com.corpgovernment.travelstandard.mapper.MbUploadErrorLogMapper;
import com.corpgovernment.travelstandard.vo.HotelAreaConfColumnVo;
import com.ctrip.corp.obt.generic.utils.CollectionUtils;
import com.ctrip.corp.obt.generic.utils.StringUtils;
import com.excel.model.ExcelImportConfig;
import com.excel.qlexpress.CommonQlFunction;
import com.excel.service.excel.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

import static com.corpgovernment.organization.dataloader.BasicDataClientLoader.*;

/**
 * 酒店淡旺季地区--暂时不动
 *
 * @author hc
 */
@Service
@Slf4j
public class HotelAreaProcessorV1<T> implements ExcelImportProcessor<UploadErrorLog,HotelAreaConfColumnVo,BizImportTask,T> {

    @Autowired
    private ExcelUtils excelUtils;

    @Autowired
    private BasicDataClientLoader basicDataClientLoader;

    @Autowired
    private CityConfigMapper cityConfigMapper;

    @Autowired
    private AreaConfigService areaConfigService;

    @Autowired
    private MbHotelAreaConfUploadMapper mbHotelAreaConfUploadMapper;

    @Autowired
    private MbUploadErrorLogMapper mbUploadErrorLogMapper;

    @Autowired
    private MbTravelstandHotelService travelstandHotelService;


    @Override
    public List<HotelAreaConfColumnVo> assembleListFromExcel(BizImportTask task) {
        return null;
    }

    @Override
    public BizImportResult<UploadErrorLog,HotelAreaConfColumnVo> assembleListFromExcel(BizImportTask task, MultipartFile file){

        BizImportResultImpl<UploadErrorLog,HotelAreaConfColumnVo> result = new BizImportResultImpl<>();

        List<UploadErrorLog> errorList = new ArrayList<>();
        List<HotelAreaConfColumnVo> multiBeanList = new ArrayList<>();

        //HotelAreaConfUpload hotelAreaConfUpload = (HotelAreaConfUpload) task.getBasic();
        XSSFWorkbook workBook = null;
        try {
            workBook = new XSSFWorkbook(file.getInputStream());
        } catch (IOException e) {
            log.error("上传差标酒店地区异常", e);
            throw new CorpBusinessException(OrganizationResponseCodeEnum.FILE_WRONG_FORMAT);
        }

        // 取出第一页
        Sheet sheet = workBook.getSheetAt(0);

        // Excel内容
        List<HotelAreaConfColumnVo> beanListFromExcel = excelUtils.getBeanListFromExcelTwo(sheet, HotelAreaConfColumnVo.class);
        
        if (CollectionUtils.isEmpty(beanListFromExcel)) {
            throw new CorpBusinessException(OrganizationResponseCodeEnum.HOTEL_TRAVEL_QUARTER_EMPTY);
        }

        beanListFromExcel.forEach(t ->  ObjectStringTrimUtils.allFieldRemoveWarp(t));

        // 平铺excel，一行多分号分割的地级市平铺为多列
        for (int i = 0; i < beanListFromExcel.size(); i++) {
            HotelAreaConfColumnVo column = beanListFromExcel.get(i);
            column.setHotelType(!"是".equals(column.getIsOversea())? AreaTypeEnum.HOTEL_TYPE_0.getCode():AreaTypeEnum.HOTEL_TYPE_1.getCode());
            if(ObjectUtil.isNull(column.getCityName())){
                multiBeanList.add(column);
            }else {
                String[] parts = column.getCityName().split("；");
                for (String part : parts) {
                    HotelAreaConfColumnVo item = new HotelAreaConfColumnVo();
                    BeanUtils.copyProperties(column,item);
                    item.setCityName(part);
                    multiBeanList.add(item);
                }
            }
        }

        // Excel 重复内容检查
        List<HotelAreaConfColumnVo> cityNameDuplicates = CommonQlFunction.getDuplicateOrgField(multiBeanList, HotelAreaConfColumnVo::getCityName); // 根据 地级市 过滤重复数据
        for (HotelAreaConfColumnVo item : cityNameDuplicates) {
            UploadErrorLog uploadErrorLog = new UploadErrorLog();
            uploadErrorLog.setType(1);
            uploadErrorLog.setFailedReason("Excel中【"+item.getCityName()+"】在多个地区配置内存在");
            uploadErrorLog.setLine(Integer.parseInt(item.getLineNo()));
            errorList.add(uploadErrorLog);
        }

        result.setErrorList(errorList);
        result.setDataList(multiBeanList);
        return result;
    }


    @Override
    public BizImportResult<UploadErrorLog,HotelAreaConfColumnVo> checkExcelData(List<HotelAreaConfColumnVo> multiBeanList) {

        BizImportResultImpl<UploadErrorLog,HotelAreaConfColumnVo> result = new BizImportResultImpl<>();

        List<UploadErrorLog> errorList = new ArrayList<>();

        for (int i = 0; i < multiBeanList.size(); i++) {
            HotelAreaConfColumnVo column = multiBeanList.get(i);
            StringBuffer errorLog = new StringBuffer();
            if (StringUtils.isBlank(column.getAreaName())) {
                errorLog.append("地区名称为空;");
            }
            if(StringUtils.isBlank(column.getProvinceName()) && StringUtils.isNotBlank(column.getCityName())){
                errorLog.append("省/自治区/直辖市/州为空;");
            }
            if(StringUtils.isBlank(column.getCityName()) && StringUtils.isNotBlank((column.getProvinceName()))){
                errorLog.append("地级市/地区/自治州/盟/国家为空;");
            }
            if(ObjectUtil.isNotEmpty(errorLog)){
                UploadErrorLog uploadErrorLog = new UploadErrorLog();
                uploadErrorLog.setType(1);
                uploadErrorLog.setFailedReason(errorLog.toString());
                uploadErrorLog.setLine(Integer.parseInt(column.getLineNo()));
                errorList.add(uploadErrorLog);
            }
        }
        result.setErrorList(errorList);
        result.setDataList(multiBeanList);
        return result;
    }


    @Override
    public BizImportPreInsertResult<UploadErrorLog, HotelAreaConfColumnVo, T> checkDbDataWithPreInsert(List<HotelAreaConfColumnVo> multiBeanList,BizImportTask task) {

        String orgId = (String) task.getExt();
        BizImportPreInsertResultImpl<UploadErrorLog, HotelAreaConfColumnVo, T> result = new BizImportPreInsertResultImpl();

        List<UploadErrorLog> errorList = new ArrayList<>();

        CityInfoQuickDisplayRequest requestInSea = new CityInfoQuickDisplayRequest();
        requestInSea.setForeignCity(false);
        requestInSea.setDisplayType(Arrays.asList(CAPITAL_CITY,MUNICIPALITY_CITY,SPECIFICALLY_CITY));
        CityInfoQuickDisplayResponse cityInfoInSeaDto = basicDataClientLoader.queryChineseCity(requestInSea);

        CityInfoQuickDisplayRequest requestOutSea = new CityInfoQuickDisplayRequest();
        requestOutSea.setForeignCity(true);
        requestOutSea.setDisplayType(Arrays.asList(COMMON_COUNTRY));
        CityInfoQuickDisplayResponse cityInfoOutSeaDto = basicDataClientLoader.queryChineseCity(requestOutSea);

        // 国内省份匹配 上海--2 北京--1
        Map<String,String> provinceInSeaNameToId = cityInfoInSeaDto.getProvinceInfoVO().stream().collect(Collectors.toMap(data -> data.getProvinceName(), data -> data.getProvinceId(), (k, v) -> k));
        // 国外省份匹配
        Map<String, ProvinceInfoVO> provinceOutSeaNameToId = cityInfoOutSeaDto.getProvinceInfoVO().stream().collect(Collectors.toMap(data -> data.getProvinceName(), data -> data, (k, v) -> k));


        // 获取当前db存在的数据，用于excel校验
        List<TravelStandardCityConfig> cityInfoList = cityConfigMapper.listByOrgId(orgId, null);

        List<TravelStandardCityConfig> confCityInfoList = new ArrayList<>();
        for (int i = 0; i < cityInfoList.size(); i++) {
            TravelStandardCityConfig item = cityInfoList.get(i);
            if(ObjectUtil.isNull(item.getCityName())){
                item.setCityCode(item.getCountryCode());
                item.setCityName(item.getCountryName());
            }
            if( AreaTypeEnum.TYPE_0.getCode().equals(item.getAreaType())){
                confCityInfoList.add(item);
            }
        }

        Map<String,TravelStandardCityConfig> cityDataMap = confCityInfoList.stream().collect(Collectors.toMap(TravelStandardCityConfig::getCityName, p -> p, (k, v) -> k));

        //查找该组织下的所有地区id
        List<AreaVo> areaConfigList = areaConfigService.getAreaConfigList(new AreaConfigVo(){{
            setOrgId(orgId);
            setStatus(NumberUtils.INTEGER_ZERO);
            setAreaType(AreaTypeEnum.TYPE_0.getCode());
        }});


        Map<Long,AreaVo> areaDataMap = areaConfigList.stream().collect(Collectors.toMap(data -> data.getId(), data -> data));
        Map<String,AreaVo> areaNameDataMap = areaConfigList.stream().collect(Collectors.toMap(data -> data.getName(), data -> data));



        for (int i = 0; i < multiBeanList.size(); i++) {
            HotelAreaConfColumnVo column = multiBeanList.get(i);
            StringBuffer errorLog = new StringBuffer();

            if(StringUtils.isBlank(column.getProvinceName()) && StringUtils.isBlank(column.getCityName())){
                if(ObjectUtil.isNotNull(areaNameDataMap.get(column.getAreaName()))){
                    errorLog.append("地区名称【"+column.getAreaName()+"】已存在;");
                }
            }
            if(ObjectUtil.isNotNull(areaNameDataMap.get(column.getAreaName()))){
                if(!areaNameDataMap.get(column.getAreaName()).getHotelType().equals(column.getHotelType())){
                    errorLog.append("该地区【是否海外配置】错误;");
                }
            }

            // 国内逻辑校验
            checkAreaInSea(cityInfoInSeaDto, provinceInSeaNameToId, column, errorLog);

            // 海外逻辑校验
            checkAreaOutSea(cityInfoOutSeaDto, provinceOutSeaNameToId, column, errorLog);

            TravelStandardCityConfig var1 = cityDataMap.get(column.getCityName());
            if(ObjectUtil.isNotNull(var1)){
                AreaVo areaVo = areaDataMap.get(var1.getAreaId());
                if(ObjectUtil.isNotNull(areaVo) && !column.getAreaName().equals(areaVo.getName())){
                    errorLog.append("【"+column.getCityName()+"】已在【"+areaVo.getName()+"】地区配置");
                }
            }


            if(ObjectUtil.isNotEmpty(errorLog)){
                UploadErrorLog uploadErrorLog = new UploadErrorLog();
                uploadErrorLog.setType(1);
                uploadErrorLog.setFailedReason(errorLog.toString());
                uploadErrorLog.setLine(Integer.parseInt(column.getLineNo()));
                errorList.add(uploadErrorLog);
            }
        }

        result.setErrorList(errorList);
        result.setDataList(multiBeanList);
        return result;
    }

    private void checkAreaInSea(CityInfoQuickDisplayResponse cityInfoInSeaDto, Map<String, String> provinceInSeaNameToId, HotelAreaConfColumnVo column, StringBuffer errorLog) {
        if (AreaTypeEnum.HOTEL_TYPE_0.getCode().equals(column.getHotelType())){
            if(StringUtils.isNotBlank(column.getProvinceName())){
                String provinceId = provinceInSeaNameToId.get(column.getProvinceName());
                if(ObjectUtil.isNull(provinceId)){
                    errorLog.append("【"+ column.getProvinceName()+"-"+column.getCityName()+"】不存在;");
                    return;
                }
                if(StringUtils.isBlank(column.getCityName())){
                    return;
                }
                List<CityBasicInfoVO> cityInSeaList = cityInfoInSeaDto.getCityInfoVO().get(provinceId);
                Optional<CityBasicInfoVO> cityBasicInfoVO = cityInSeaList.stream() .filter(a -> column.getCityName().equals(a.getCityName())) .findFirst();
                if (!cityBasicInfoVO.isPresent()) {
                    errorLog.append("【"+ column.getProvinceName()+"】下"+ column.getCityName()+"不存在;");
                    return;
                }else{
                    column.setCityCode(cityBasicInfoVO.get().getCityCode());
                }
            }
        }
    }



    private void checkAreaOutSea(CityInfoQuickDisplayResponse cityInfoOutSeaDto, Map<String, ProvinceInfoVO> provinceOutSeaNameToId, HotelAreaConfColumnVo column, StringBuffer errorLog) {
        // 国内逻辑校验
        if (AreaTypeEnum.HOTEL_TYPE_1.getCode().equals(column.getHotelType())){
            if(StringUtils.isNotBlank(column.getProvinceName())){
                ProvinceInfoVO provinceInfoVO = provinceOutSeaNameToId.get(column.getProvinceName());
                if(ObjectUtil.isNull(provinceInfoVO)){
                    errorLog.append("【"+column.getProvinceName()+"】不存在;");
                    return;
                }
                if(StringUtils.isBlank(column.getCityName())){
                    return;
                }
                List<CityBasicInfoVO> cityOutSeaList = cityInfoOutSeaDto.getCityInfoVO().get(column.getProvinceName());
                Optional<CityBasicInfoVO> cityBasicInfoVO = cityOutSeaList.stream() .filter(a -> column.getCityName().equals(a.getCityName())) .findFirst();
                if (!cityBasicInfoVO.isPresent()) {
                    errorLog.append("【"+column.getProvinceName()+"】下"+column.getCityName()+"不存在;");
                    return;
                }else{
                    column.setCityCode(cityBasicInfoVO.get().getCityCode());
                }
            }
        }
    }


    @Override
    public void writeErrorLog(List<UploadErrorLog> uploadErrorLogs, BizImportTask bizImportTask) {

        HotelAreaConfUpload hotelAreaConfUpload = (HotelAreaConfUpload) bizImportTask.getBasic();
        // 更新日志
        int errorNum = uploadErrorLogs.stream().collect(Collectors.groupingBy(UploadErrorLog::getLine)).size();
        hotelAreaConfUpload.setFailNumber(errorNum);
        hotelAreaConfUpload.setSuccessNumber(hotelAreaConfUpload.getUploadNumber() - errorNum);
        hotelAreaConfUpload.setStatus(QuarterImportExcelRecordStatusEnum.F.getDealCode());
        mbHotelAreaConfUploadMapper.updateByPrimaryKeySelective(hotelAreaConfUpload);

        // 批量写入error日志
        for (int i = 0; i < uploadErrorLogs.size(); i++) {
            UploadErrorLog item = uploadErrorLogs.get(i);
            item.setBizId(hotelAreaConfUpload.getId());
        }
        if (CollectionUtils.isNotEmpty(uploadErrorLogs)) {
            mbUploadErrorLogMapper.insertList(uploadErrorLogs);
        }
    }

    @Override
    public void writeIfVerifyPassed(List<HotelAreaConfColumnVo> dataList, BizImportTask bizImportTask) {

        HotelAreaConfUpload hotelAreaConfUpload = (HotelAreaConfUpload) bizImportTask.getBasic();
        String orgId = (String) bizImportTask.getExt();
        // 需要新增的海外
        List<HotelAreaConfColumnVo> finalNeedAddOutSeaCityList  = dataList.stream()
                .filter(item -> AreaTypeEnum.HOTEL_TYPE_1.getCode().equals(item.getHotelType()))
                .collect(Collectors.toList()); // 转换为 List
        // 需要新增国内
        List<HotelAreaConfColumnVo> finalNeedAddInSeaCityList = dataList.stream()
                .filter(item -> AreaTypeEnum.HOTEL_TYPE_0.getCode().equals(item.getHotelType()))
                .collect(Collectors.toList()); // 转换为 List
        // 更新db
        travelstandHotelService.saveHotelAreaConf(orgId, finalNeedAddOutSeaCityList, finalNeedAddInSeaCityList);

        hotelAreaConfUpload.setSuccessNumber(dataList.size());
        hotelAreaConfUpload.setFailNumber(0);
        hotelAreaConfUpload.setStatus(QuarterImportExcelRecordStatusEnum.E.getDealCode());
        mbHotelAreaConfUploadMapper.updateByPrimaryKeySelective(hotelAreaConfUpload);
    }


    @Override
    public String getTag() {
        return "hotel_area_v1";
    }

    @Override
    public ExcelImportConfig getConfig() {
        ExcelImportConfig config = new ExcelImportConfig();
        config.setIsSharding(true);
        config.setIgnoreHeader(true);
        config.setRollBackType(1);
        return config;
    }

}
